﻿using System;
using System.Globalization;
using System.Text;
using System.Threading.Tasks;
using System.Timers;

using ppatierno.AzureSBLite.Messaging;

namespace Eldert.IoT.Simulator
{
    class Simulator
    {
        private static readonly bool _multiShipMode = true;
        private static readonly EventHubClient _eventHub = EventHubClient.CreateFromConnectionString(Settings.Read("FieldHubEventHubConnectionString"), Settings.Read("FieldHubEventHub"));
        private static readonly SubscriptionClient _topic = SubscriptionClient.CreateFromConnectionString(Settings.Read("EngineAdministrationTopicConnectionString"),
            Settings.Read("EngineAdministrationTopic"), Settings.Read("ShipName"));

        static void Main()
        {
            #region Create sensor readings timer

            var sensorReadingsTimer = new Timer { AutoReset = true, Enabled = true, Interval = 5000 };
            sensorReadingsTimer.Elapsed += (sender, eventArgs) =>
            {
                GetSimulatedSensorReadings();
            };
            sensorReadingsTimer.Start();

            #endregion

            #region Create error throwing timer

            var errorsTimer = new Timer { AutoReset = true, Enabled = true, Interval = 30000 };
            errorsTimer.Elapsed += (sender, eventArgs) =>
            {
                var exception = new Exception($"Exception created for queue demo at {DateTime.UtcNow.ToString(CultureInfo.InvariantCulture)}");
                exception.Log();
            };
            sensorReadingsTimer.Start();

            #endregion

            #region Action on receiving message in topic

            _topic.OnMessage(message =>
            {
                var newMaximumTemperature = message.Properties["maximumtemperature"];
                Settings.Write("MaximumTemperature", newMaximumTemperature.ToString());
                Console.WriteLine($"Maximum temperature has been set to {newMaximumTemperature}");
            });

            #endregion

            Console.WriteLine("Press any key to continue...");
            Console.ReadKey();
        }

        /// <summary>
        /// Get readings from sensors.
        /// </summary>
        private static void GetSimulatedSensorReadings()
        {
            #region Get ship names

            var ships = new[] { Settings.Read("ShipName") };

            if (_multiShipMode)
            {
                ships = Settings.Read("Ships").Split(';');
            }

            #endregion

            // Loop through the ships (depending on _multiShipMode one or multiple)
            Parallel.ForEach(ships, shipName =>
            {
                // Simulate temperature
                var temperature = new Random().Next(400, 700);
                Console.WriteLine($"Ship: {shipName} - Temperature: {temperature}");

                // Check if a warning should be generated
                var warning = temperature > Convert.ToInt32(Settings.Read("MaximumTemperature"));

                try
                {
                    // Create engine information object, simulate some of the input
                    var engineInformation = new EngineInformation
                    {
                        ShipName = shipName,
                        EngineName = Settings.Read("EngineName"),
                        CreatedDateTime = DateTime.UtcNow,
                        RPM = new Random().Next(400, 1000),
                        Temperature = temperature,
                        Warning = warning,
                        EngineWarning = new Random().Next(0, 10) > 9 ? new Random().Next(1, 3) : 0
                    };

                    // Serialize to JSON
                    var serializedString = engineInformation.Serialize();

                    // Create brokered message
                    // Send with shipname as partitionkey, to make sure messages for 1 ship are processed in correct order
                    var message = new EventData(Encoding.UTF8.GetBytes(serializedString));
                    message.Properties.Add("haswarning", engineInformation.Warning);
                    message.PartitionKey = engineInformation.ShipName;

                    // Send to event hub
                    _eventHub.Send(message);
                }
                catch (Exception exception)
                {
                    exception.Log();
                }
            });
        }
    }
}